﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Sofire.Expressions;
using System.Xml.Linq;

namespace Sofire.Data.XSql
{
    internal abstract class XSqlTestNodeBase : XSqlNodeBase, IXSqlTest
    {
        private string _Test;
        public virtual string Test
        {
            get
            {
                return this._Test;
            }
            set
            {
                this._Test = value;
            }
        }

        private string _TestPrefix;
        public string TestPrefix
        {
            get
            {
                return this._TestPrefix;
            }
            set
            {
                this._TestPrefix = value;
            }
        }

        protected override void Load(XmlNode node)
        {
            this._Test = this.TryGetAttribute(node, XSqlAttributes.Test);
            if(this._Test == null)
            {
                if(node.HasChildNodes && node.FirstChild.Name == XSqlAttributes.Test)
                {
                    this._Test = node.FirstChild.InnerText;
                    if(this._Test != null) return;
                }
                this.ThrowException(XSqlError.UnfoundTest);
            }
        }

        protected XElement CreateXTest(string nodeName)
        {
            XElement element = new XElement(nodeName);
            var test = this.Test;
            if(test != null)
            {
                if(test.IndexOfAny(XmlEscapes) > -1)
                {
                    element.Add(new XElement(XSqlAttributes.Test, new XCData(test)));
                }
                else
                {
                    element.SetAttributeValue(XSqlAttributes.Test, test);
                }
            }

            this.CreateXChildren(element);
            return element;
        }

        public virtual string GetTest(XSqlParameterCollection parameters)
        {
            //if(this._Test == null)
            //{
            //    lock(this)
            //    {
            //        if(this._Test == null)
            //        {
            //            var firstNode = this.Children.FirstNode;
            //            if(firstNode == null || firstNode.Type != XSqlType.Test)
            //            {
            //                if(this.Type == XSqlType.Switch) return null;
            //                this.ThrowException(XSqlError.UnfoundTest);
            //            }
            //            var test = firstNode.Compile(parameters);
            //            this._Test = test;
            //        }
            //    }
            //}
            return this._TestPrefix + this._Test;
        }

        private Expression TestExpression;

        public virtual Expression CreateExpression(XSqlParameterCollection parameters)
        {
            return this.CreateExpression(parameters, false);
        }

        public virtual Expression CreateExpression(XSqlParameterCollection parameters, bool renew)
        {
            if(renew)
            {
                lock(this) TestExpression = null;
            }
            if(TestExpression == null) lock(this) if(TestExpression == null) TestExpression = this.Document.CreateExpression(this.GetTest(parameters));
            return TestExpression;
        }

        public virtual bool CompileTest(XSqlParameterCollection parameters)
        {
            this.CreateExpression(parameters);

            EvaluateParameterHandler handler = (name, args) =>
            {
                args.Result = parameters.GetValue(name);
            };
            this.TestExpression.EvaluateParameter += handler;
            try
            {
                var r = TestExpression.Evaluate();
                return object.Equals(r, true);
            }
            finally
            {
                this.TestExpression.EvaluateParameter -= handler;
            }
        }
    }
}
